<?php
/**
 * Description:
 * Author: hezhizheng
 * Date: 2018/11/28
 * Time: 14:44
 * Created by Created by Panxsoft.
 */

namespace App\Services\Orders;

use App\Models\Extension\Extension;
use App\Models\Order\Order;
use App\Models\Order\OrderHistory;
use App\Models\Products\Product;
use App\Models\Products\ProductOptionValue;
use App\Models\Setting;
use App\Services\Utils\Transaction;
use Illuminate\Support\Facades\DB;

class PayNotifyService
{

    /**
     * 已支付，保存/修改订单完成支付的数据
     * @test
     * @param Order $order
     * @throws \Exception
     */
    public function savePaidStatus(Order $order): void
    {
        Transaction::handle(function () use ($order) {
            $order_status_id = $this->getOrderCompletedStatusId($order);

            // 修改订单状态，已支付
            $this->saveOrderStatus($order, $order_status_id);

            // 写入订单历史记录表 order_history
            $this->saveOrderHistory($order);


            // 减去商品/商品选项库存 quantity
            $order_products = $order->orderProducts()->get();
            $order_options = $order->orderOptions()->with('orderProduct')->get();

            foreach ($order_products as $order_product) {
                (new Product)->where([
                    ['product_id', $order_product->product_id],
                    ['quantity', '>=', $order_product->quantity] // 防止库存为负数
                ])->decrement('quantity', $order_product->quantity);
            }

            // todo 这里数量有问题。根据product_option_value中的subtract判断。
            foreach ($order_options as $order_option) {
                $product_option_value = ProductOptionValue::getProductOptionValue($order_option->product_option_value_id);
                $subtract = $product_option_value->subtract ?? ProductOptionValue::PRODUCT_OPTION_VALUE_NO_SUBTRACT;
                if($subtract !== ProductOptionValue::PRODUCT_OPTION_VALUE_SUBTRACT) {
                    continue;
                }

                (new ProductOptionValue)->where([
                    ['product_option_id', $order_option->product_option_id],
                    ['product_option_value_id', $order_option->product_option_value_id],
                    ['quantity', '>=', $order_option->orderProduct->quantity] // 防止库存为负数
                ])->decrement('quantity', $order_option->orderProduct->quantity);
            }

        });
    }

    /**
     * @test
     * todo 手动维护事务，防止超卖
     * 库存更改失败就回滚，但是用户可能已经支付成功了，直接退款？
     * @param Order $order
     */
    public function transactionSavePaidStatus(Order $order): void
    {
        try {
            DB::beginTransaction();
            $order_status_id = $this->getOrderCompletedStatusId($order);

            // 修改订单状态，已支付
            $this->saveOrderStatus($order, $order_status_id);

            // 写入订单历史记录表 order_history
            $this->saveOrderHistory($order);

            // 减去商品/商品选项库存 quantity
            $order_products = $order->orderProducts()->get();
            $order_options = $order->orderOptions()->with('orderProduct')->get();

            foreach ($order_products as $order_product) {
                $update_product_quantity = (new Product)->where([
                    ['product_id', $order_product->product_id],
                    ['quantity', '>=', $order_product->quantity] // 防止库存为负数
                ])->decrement('quantity', $order_product->quantity);

                if (!$update_product_quantity) {
                    DB::rollBack();
                }
            }

            foreach ($order_options as $order_option) {
                $update_product_option_value = (new ProductOptionValue)->where([
                    ['product_option_id', $order_option->product_option_id],
                    ['product_option_value_id', $order_option->product_option_value_id],
                    ['quantity', '>=', $order_option->orderProduct->quantity] // 防止库存为负数
                ])->decrement('quantity', $order_option->orderProduct->quantity);

                if (!$update_product_option_value) {
                    DB::rollBack();
                }
            }
        } catch (\Exception $exception) {
            DB::rollBack();
        }

        DB::commit();
    }


    /**
     * @param Order $order
     * @return int
     */
    public function getOrderCompletedStatusId(Order $order)
    {
        switch ($order->payment_code) {
            case Extension::CODE_PAYMENT_ALI:
                return Setting::findConfigByCode(Setting::CODE_PAYMENT_ALI)['payment_alipay_order_status_id'];
            case Extension::CODE_PAYMENT_WECHAT:
                return Setting::findConfigByCode(Setting::CODE_PAYMENT_WECHAT)['payment_wechat_pay_completed_status_id'];
            case Extension::CODE_PAYMENT_PAYPAL:
                return Setting::findConfigByCode(Setting::CODE_PAYMENT_PAY_PAL)['payment_pp_express_completed_status_id'];
            case Extension::CODE_PAYMENT_COD:
                return Setting::findConfigByCode(Setting::CODE_PAYMENT_COD)['payment_cod_order_status_id'];
            default :
                return Setting::findConfigByCode(Setting::CODE_PAYMENT_WECHAT)['config_order_status_id'];
        }
    }

    /**
     * @param Order $order
     * @param $order_status_id
     */
    private function saveOrderStatus(Order $order, $order_status_id): void
    {
        $order->update([
            'order_status_id' => $order_status_id,
            'date_modified'   => (string)now(),
        ]);
    }

    /**
     * @param Order $order
     */
    private function saveOrderHistory(Order $order): void
    {
        (new OrderHistory)->create([
            'order_id'        => $order->order_id,
            'order_status_id' => $order->order_status_id,
            'date_added'      => (string)now(),
        ]);
    }
}